package fr.imag.ufrima.ima.project.ui.main;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyVetoException;
import java.io.File;
import java.util.HashMap;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JScrollPane;

import org.apache.log4j.Logger;
import org.noos.xing.mydoggy.plaf.MyDoggyToolWindowManager;

import fr.imag.ufrima.ima.project.core.ImageOperation;
import fr.imag.ufrima.ima.project.ui.component.FileManager;
import fr.imag.ufrima.ima.project.ui.component.Menu;
import fr.imag.ufrima.ima.project.ui.component.StatusBar;
import fr.imag.ufrima.ima.project.ui.component.ToolsPanel;
import fr.imag.ufrima.ima.project.ui.listerners.SelectorListener;
import fr.imag.ufrima.ima.project.ui.listerners.StatusBarListener;
import fr.imag.ufrima.ima.project.ui.utils.ImageFilter;
import fr.imag.ufrima.ima.project.ui.utils.Utils;

@SuppressWarnings("serial")
public class ImageProject extends JFrame implements WindowListener {
	private Logger logger = Logger.getLogger(getClass().getName());

	private JDesktopPane theDesktop;

	private int idDocuments;
	private HashMap<Integer, ImageDocument> openImages;

	private MyDoggyToolWindowManager myDoggyToolWindowManager;
	private ToolsPanel toolPanel;
	private Menu menuBar;
	private StatusBar sb;
	private StatusBarListener sbm;
	private SelectorListener sl;
	private FileManager fm;

	private Cursor waitCursor;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ImageProject frame = new ImageProject();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public ImageProject() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setTitle("Projet Image");
		setBounds(100, 20, 1000, 700);

		theDesktop = new JDesktopPane(); // create desktop pane
		// add(theDesktop); // add desktop pane to frame

		idDocuments = 0;
		openImages = new HashMap<Integer, ImageDocument>();
		waitCursor = new Cursor(Cursor.WAIT_CURSOR);

		initComponents();
		addWindowListener(this);
	}

	private void initComponents() {
		// create the menu bar
		menuBar = new Menu(ImageProject.this);

		// create the StatusBar
		sb = new StatusBar();

		// add the StatusBar to the main frame
		this.add(sb, BorderLayout.PAGE_END);

		// create the Status Manager
		sbm = new StatusBarListener(ImageProject.this);

		// create the file manager for opening and saving files
		fm = new FileManager(ImageProject.this);

		// create the Selector Manager
		sl = new SelectorListener(this);

		// create de tool panel
		myDoggyToolWindowManager = new MyDoggyToolWindowManager();
		toolPanel = new ToolsPanel(this, myDoggyToolWindowManager);
		toolPanel.initContentManager(theDesktop);
		add(myDoggyToolWindowManager);
	}

	public void openImage() {
		logger.info(String.format("Menu open image..."));
		File file = fm.openFileDialog();

		if (file != null) {

			// create internal frame
			JInternalFrame frame = new JInternalFrame(null, true, true, true, true);

			ImageDocument imageDocument = new ImageDocument(idDocuments, file.getAbsolutePath(), frame,
					ImageProject.this);

			imageDocument.addMouseListener(sbm);
			imageDocument.addMouseMotionListener(sbm);

			imageDocument.addMouseListener(sl);
			imageDocument.addMouseMotionListener(sl);

			openImages.put(idDocuments, imageDocument);
			JScrollPane scrollPane = new JScrollPane(imageDocument, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
					JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

			// Put an identifier to be able to recover the image latter
			frame.setName(Integer.toString(idDocuments));

			// Add the scrolling
			frame.add(scrollPane, BorderLayout.CENTER); // add panel

			// Auto-adjust the size
			frame.pack(); // set internal frame to size of contents

			// add listener to frame event
			frame.addInternalFrameListener(imageDocument);

			theDesktop.add(frame); // attach internal frame

			frame.setVisible(true); // show internal frame

			toolPanel.hideAll();

			idDocuments++;
			if (this.isImageDocumentAvailable()) {
				imageDocumentIsAvailable();
			}

			logger.info(String.format("Open image: %s", imageDocument.getName()));
		}
	}

	public void saveImage() {
		logger.info(String.format("Menu save image..."));

		ImageDocument im = this.getCurrentImageDocument();
		im.getImage().saveToFile(im.getName(), Utils.getExtension(im.getName()));
		im.repaint();

		logger.info(String.format("Saved image: %s", im.getName()));
	}

	public void saveImageAs() {
		logger.info(String.format("Menu save image as..."));

		File saveToFile = fm.saveFileDialog();

		if (saveToFile != null) {
			String extension = ((ImageFilter) (fm.getFileFilter())).getTypeFilter();
			String saveFileName = saveToFile.getAbsolutePath();
			if (!Utils.getExtension(saveToFile).equals(extension)) {
				saveFileName = saveFileName + "." + extension;
			}

			ImageDocument im = this.getCurrentImageDocument();
			im.getImage().saveToFile(saveFileName, extension);
			im.repaint();

			logger.info(String.format("Saved image: %s type: %s", saveFileName, extension));
		}
	}

	public void exit() {
		JInternalFrame frame = null;
		ImageDocument im = null;

		if (isImageDocumentAvailable()) {
			JInternalFrame[] allFrames = theDesktop.getAllFrames();
			for (int i = 0; i < allFrames.length; i++) {
				frame = allFrames[i];
				int id = Integer.valueOf(frame.getName());
				im = openImages.get(id);

				if (im.getImage().isModified()) {
					try {
						frame.setClosed(true);
					} catch (PropertyVetoException e) {
						logger.info(String.format("Exception while closing frame %s: %s", im.getName(), e.getMessage()));
						e.printStackTrace();
					}
				}
			}
		}

		this.dispose();
	}

	public void applyOperation(ImageOperation imageOperation) {
		this.setWaitCursor();

		BufferedImage resultImage = imageOperation.doOperation();

		this.getCurrentImageDocument().getImage().modifyWithImage(resultImage);
		this.getCurrentImageDocument().repaint();
		
		JInternalFrame jInternalFrame = this.getCurrentInteralFrame();
		jInternalFrame.pack();
		
		this.setNormalCursor();
	}

	public void annuler() {
		this.getCurrentImageDocument().getImage().annuler();
	}

	public void valider() {
		this.getCurrentImageDocument().getImage().valider();
	}

	public ImageDocument getCurrentImageDocument() {
		JInternalFrame frame = null;
		ImageDocument im = null;

		logger.debug(String.format("Looking for getCurrentImageDocument()..."));

		if (isImageDocumentAvailable()) {
			JInternalFrame[] allFrames = theDesktop.getAllFrames();
			for (int i = 0; i < allFrames.length; i++) {
				frame = allFrames[i];
				if (frame.isSelected()) {
					logger.debug(String.format("Active JInternalFrame: %s", frame.getName()));
					break;
				}
			}

			int id = Integer.valueOf(frame.getName());
			im = openImages.get(id);
		}

		logger.debug(String.format("Current Image: %s", im));

		return im;
	}

	public JInternalFrame getCurrentInteralFrame() {
		JInternalFrame frame = null;

		JInternalFrame[] allFrames = theDesktop.getAllFrames();
		for (int i = 0; i < allFrames.length; i++) {
			frame = allFrames[i];
			if (frame.isSelected()) {
				break;
			}
		}

		return frame;
	}

	public void imageDocumentIsAvailable() {
		menuBar.showMenuOptionsForAvailableImages();
		toolPanel.setAllToolsAvailability(true);
		toolPanel.getToolWindowUtil().setVisible(true);
	}

	public void imageDocumentIsNotAvailable() {
		menuBar.hideMenuOptionsForAvailableImages();
		toolPanel.setAllToolsAvailability(false);
	}

	public boolean isImageDocumentAvailable() {
		return theDesktop.getAllFrames().length > 0;
	}

	/**
	 * @author lancelog
	 * @return the StatusBar 's Object
	 */
	public StatusBar getStatusBar() {
		return sb;
	}

	public SelectorListener getSelectorListener() {
		return this.sl;
	}

	public void setWaitCursor() {
		this.setCursor(waitCursor);
	}

	public void setNormalCursor() {
		this.setCursor(Cursor.getDefaultCursor());
	}

	public ToolsPanel getToolsPanel() {
		return this.toolPanel;
	}

	public FileManager getFm() {
		return fm;
	}

	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		// TODO Auto-generated method stub
		this.exit();
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

}
